import sys
sys.path.append('../')
#import copy
import numpy as np
from board_fast import Board,Game,Player,Point,Move
'''
alphago网络的第一层是我们手工提取特征，我们用

在一些手工特征上，我们并没有通过1和-1来区分黑棋还是白棋，但是这么做是完全可以的

'''

#注意，board是从1开始索引的,numpy从0开始索引
def to_plane_color(board,player):
    if player==Player.black:
        color=1
    else:
        color=-1
    npdata=board.print_board(isprint=False)
    plane_now=np.zeros(npdata.shape)    #存放当前玩家在棋盘上的子，也暗示了当前是谁落子
    plane_now[npdata==color]=1
    plane_other=np.zeros(npdata.shape)    #存放对方在棋盘上的子
    plane_other[npdata==-1*color]=1
    plane_empty=np.zeros(npdata.shape)
    plane_empty[npdata==0]=1
    #格式N,C,H,W,channels_first
    plane_now=plane_now[np.newaxis,:]
    plane_other=plane_other[np.newaxis,:]
    plane_empty=plane_empty[np.newaxis,:]
    return np.vstack((plane_now,plane_other,plane_empty))

def to_ones(board):
    npdata=board.print_board(isprint=False)
    return np.ones(npdata.shape)[np.newaxis,:]

def to_zeros(board):
    npdata=board.print_board(isprint=False)
    return np.zeros(npdata.shape)[np.newaxis,:]

def to_legal_moves(board,player):
    def isLegal(point,board,player):    #包括不会堵死自己的眼位和自杀
        neighbours=board.get_neighbors(point)
        is_eye=True
        is_self_captured=True
        the_other_strings=[]
        own_strings=[]
        liberties=[]
        #判断是不是眼位
        for i in neighbours:
            if board.grid.get(i)==None:
                is_eye=False
                break
            elif board.grid.get(i).player != player:
                is_eye=False
                break
            elif len(board.grid.get(i).liberties)<=1:
                is_eye=False
                break
            else:
                pass
        #判断是不是自杀
        for i in neighbours:
            go_string_t=board.grid.get(i)
            if go_string_t is not None: #有人占据了
                if go_string_t.player == player:    #自己的
                    if go_string_t not in own_strings:
                        own_strings.append(go_string_t)
                else:
                    if go_string_t not in the_other_strings:
                        the_other_strings.append(go_string_t)
            else:   #空子
                liberties.append(i)
        if len(liberties) == 0:
            if any(len(str.liberties) == 1 for str in the_other_strings):   #如果落子前对方有任一串棋只有一口气了，就是提子
                is_self_captured=False
            elif all(len(str.liberties) == 1 for str in own_strings):
                None    #自杀
            else:
                is_self_captured=False
        else:
            is_self_captured=False
        if is_eye or is_self_captured:
            return False
        return True
    npdata=board.print_board(isprint=False)
    plane=np.zeros(npdata.shape)
    plane[npdata==0]=1    #先找出可以落子的地方
    candidates=np.argwhere(plane==1)
    for i in candidates:
        point=Point(i[0]+1,i[1]+1)  #board是1,1开始索引(原点在左上角)
        if not isLegal(point,board,player):
            plane[tuple(i)]=0
    return plane[np.newaxis,:]

board_his=[] #保存棋盘历史
def turn_since(board,not_reset=False,boardhis=None):  #这个层有8层，表示棋盘上的落子是多少步以前的，alphago就保存8步，认为8步以前的落子是等价的，或者一般只用关心最近的8步
    if boardhis is None:
        global board_his
        boardhis=board_his
    if not not_reset:
        for _ in range(len(boardhis)):
            boardhis.pop()
    npdata=board.print_board(isprint=False)
    if len(boardhis)>7:
        for i in range(len(boardhis)-1):
            boardhis[i]=boardhis[i+1]
        boardhis[7]=npdata
    else:
        boardhis.append(npdata)
    #board_his[0]保存8步以前的内容,除了board_his[0]，其它的每个plane就只有一个子
    planes=np.zeros((8,*npdata.shape))
    for idx,item in enumerate(boardhis):
        np_move=np.zeros(npdata.shape)
        if idx==0:
            planes[idx][item!=0]=1
        else:
            boardhis[idx-1][boardhis[idx]==0]=0
            planes[idx][boardhis[idx-1]!=boardhis[idx]]=1

    return planes

def liberties(board):
    npdata=board.print_board(isprint=False)
    planes=np.zeros((8,*npdata.shape))  #保存最多8口气的子的位置
    for r in range(board.height):
        for c in range(board.width):
            point=Point(r+1,c+1)
            if board.get_go_string(point):
                liberity=len(board.get_go_string(point).liberties)
            else:
                liberity=0
            liberties = min(liberity, 8)
            if liberties>0:
                planes[liberties-1,r,c]=1
    return planes

def three_in_one(board,player):    #将落子后的气，吃子和叫吃合并在一起实现，因为这里要模拟下一步
    npdata=board.print_board(isprint=False)
    planes_liberties=np.zeros((8,*npdata.shape))
    planes_captures=np.zeros((8,*npdata.shape))
    planes_atari=np.zeros((8,*npdata.shape))
    for r in range(board.height):
        for c in range(board.width):
            point = Point(row=r + 1, col=c + 1)
            if not board.play_stone(player,point):  #非法
                board.restore_board()
                continue
            else:
                go_string = board.get_go_string(point)
                liberties = min(len(go_string.liberties), 8)
                if liberties>0:
                    planes_liberties[liberties-1][r][c]=1
                capture_count=0
                nb_strings=[board.get_go_string(nb) for nb in point.neighbors()]
                other_player = player.other()
                for i in nb_strings:
                    if i and len(i.liberties) == 1 and i.player == other_player:
                        capture_count += len(i.stones)
                captures = min(capture_count, 8)
                if captures>0:
                    planes_captures[captures-1][r][c]=1
                if go_string and len(go_string.liberties)==1:
                    num_atari_stones = min(len(go_string.stones), 8)
                    if num_atari_stones>0:
                        planes_atari[num_atari_stones-1][r][c]=1
                board.restore_board()
    return np.vstack((planes_liberties,planes_captures,planes_atari))
'''征子，抓和逃（暂时还没实现）
def
'''
